/**
 * @author Kristian Mandrup
 * @date June 10, 2009
 * @version 0.1
 * 
 * m3gen :: Utils
 */ 

/*
 * http://web-graphics.com/mtarchive/001709.php
 * 
 * At the bottom
 * 
 */
/*
Function.prototype.defaults = function(origArgs) {
    for (var i = 0, j = 1; j < arguments.length; i++, j++) {
        if (typeof origArgs[i] == 'undefined')
            origArgs[i] = arguments[j];
    }
};
*/

// FROM: http://parentnode.org/javascript/default-arguments-in-javascript-functions/

Function.prototype.defaults = function()
{
  var _f = this;
  var _a = Array(_f.length-arguments.length).concat(
    Array.prototype.slice.apply(arguments));
  return function()
  {
    return _f.apply(_f, Array.prototype.slice.apply(arguments).concat(
      _a.slice(arguments.length, _a.length)));
  }
}
/*
Function.prototype.defaults = function(o) {
	var _f = this;
	var args = Array.prototype.slice.call(arguments, 1);
	return function() {
		var a = Array.prototype.slice.call(arguments);
		return _f.apply(o, a.concat(args.slice(a.length)));
	}
}
*/
m3gen.util = {
	trim: function(str){
		return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	},	
	// can fx be used to merge with default arguments of a function
	merge: function (obj, defaultObj){
			var result = {};
		    for(var p in defaultObj){
		        if(obj[p] === undefined) result[p] = defaultObj[p];
		    }
		    for(var p in obj){
		        if(result[p] === undefined) result[p] = obj[p];
		    }			
		    return result;
	},
	getTheContext: function(that) {
		return m3gen.util.getObjDef(that, that.context);
	}, 	
	getObjDef: function(obj, defaultObj) {
		var vObj = m3gen.util.validObj(obj);
		if (vObj)
			return vObj;
		else return defaultObj; 
	},
	validObj: function(obj) {
		if (obj == undefined) 
			return null; 
		else return obj;
	},

	getAnObj: function(obj) {
		if (obj == undefined) 
			return {}; 
		else return obj;
	},

	isValidObj: function(obj) {
		return (obj && obj != undefined);
	},

	isValidString: function(obj) {
		return (m3gen.util.isValidObj(obj) && m3gen.util.isString(obj));
	},

	isValidGlobalExecState: function(globalExecState) {
		return m3gen.util.isValidObj(globalExecState) && m3gen.util.isValidObj(globalExecState.objTypeCounter);
	},

	isValidBranchState: function(state) {
		return state == 'open' || state == 'closed';
	},

	isValidNodeObj: function(nodeObj) {
		return m3gen.util.isValidObj(nodeObj) && m3gen.util.isValidString(nodeObj.id);
	},

	isValidRuleSet: function(ruleSet) {
		return m3gen.util.isValidObj(ruleSet);
	},

	isValidRuleSetConfiguration: function(ruleSetConfiguration) {
		return m3gen.util.isValidObj(ruleSetConfiguration) && m3gen.util.isValidObj(ruleSetConfiguration.ruleSets);
	},

	isValidGeneratorModel: function(generatorModel) {
		return m3gen.util.isValidObj(generatorModel) && 
			m3gen.util.isValidRuleSetConfiguration(generatorModel.ruleSetConfiguration);
	},

	isValidObjType: function(objType) {
		return m3gen.util.isValidObj(objType);
	},

	isValidOptions: function(options) {	
		return m3gen.util.isValidObj(options);
	},

	invalidOptions: function(options) {	
		return !m3gen.util.isValidObj(options);
	},

	isValidJsTreeNode: function (jsTreeNode, context) {
		if (jsTreeNode.attributes) return jsTreeNode.attributes.id;
		else {
			if (context)
				context.eventController.handle('onInvalidJsTreeNodeWarning');
			return false;
		}
	},

	isNotEmptyArray: function(array) {
		return (m3gen.util.isValidObj(array) && array.length >0);	
	},
	
	isEmptyArray: function(array) {
		return (!m3gen.util.isValidObj(array) || array.length == 0);	
	},

	isEmptyObj: function (obj) {
		if (m3gen.util.validObj(obj)) {	
		    for(var prop in obj) {
		        if(obj.hasOwnProperty(prop))
		            return false;
		    }
		}
	    return true;
	},

	
	/**
	 * jsTree node specific utility function to ensure list of nodes are unique (no items with duplicate Ids)
	 * @param {Object} noitemswithduplicateIds
	 */
	getUniqueArray: function (array) {
		var r = new Array();
		o:for(var i = 0, n = array.length; i < n; i++)
		{
			for(var x = 0, y = r.length; x < y; x++)
			{
				if (r[x].attributes && array[i].attributes) {
					if (r[x].attributes.id == array[i].attributes.id) {
						continue o;
					}
				}
			}
			r[r.length] = array[i];
		}
		return r;
	},
	
	convertToId : function(title) {
		return title.replace(/(\s| | )+/gi, "_");
	},
	
	// utility function to flatten nested arrays
	flatten: function(arrays){
		return arrays.reduce(function(a, b){
			return a.concat(b);
		}, []);
	},	
	oc: function (a)
	{
	  var o = {};
	  for(var i=0;i<a.length;i++)
	  {
	    o[a[i]]='';
	  }
	  return o;
	},	
	typeOf: function (value) {
		if (!m3gen.util.isValidObj(value)) return null;
	    var s = typeof value;
	    if (s === 'object') {
	        if (value) {
	            if (typeof value.length === 'number' &&
	                    !(value.propertyIsEnumerable('length')) &&
	                    typeof value.splice === 'function') {
	                s = 'array';
	            }
	        } else {
	            s = 'null';
	        }
	    }
	    return s;
	},	
	isArray: function(value) {
		return m3gen.util.typeOf(value) === 'array';
	},	
	isFunction: function(value) {
		return m3gen.util.typeOf(value) === 'function';
	},
	isString: function(value) {
		return m3gen.util.typeOf(value) === 'string';
	},	
	/**
	 * 
	 * @param {Object} arr1
	 * @param {Object} arr2
	 */
	concatArrays:  function (arr1, arr2, condition) {
		// TODO: Remove duplicate children!
		if (this.isArray(arr2)) {
			arr2.forEach(function(elem){
				var doPush = true;
				if (m3gen.util.isFunction(condition)) {
					doPush = condition(elem, arr1, arr2);
				} 
				if (doPush)
					arr1.push(elem);
			});
		} else {
			var doPush = true;
			if (m3gen.util.isFunction(condition)) {
				doPush = condition(arr2);
			} 	
			if (doPush)
				arr1.push(arr2);					
		}	
	},
	/**
	 * 
	 * @param {Object} arr1
	 * @param {Object} arr2
	 */
	concatJsTreeNodeArrays:  function (arr1, arr2, condition) {
		// TODO: Remove duplicate children!
		for each (var elem in arr2){
			if (m3gen.util.isValidJsTreeNode(elem))
				arr1.push(elem);
		}	
	},
	concatNodeObjArrays:  function (arr1, arr2, condition) {
		// TODO: Remove duplicate children!
		for each (var elem in arr2){
			if (m3gen.util.isValidNodeObj(elem)) {
				var doPush = true;
				if (m3gen.util.isFunction(condition)) {
					doPush = condition(elem);
				}
				if (doPush)
					arr1.push(elem);
			}
		}	
	}			
	
}

m3gen.util.event = {

	/**
	 * Construct an eventObj using context only
	 * @param {Object} context
	 */
	getEventObjVP: function(context) {
		var eventObj = {};			
		eventObj.context = context;		
		return eventObj;
	},
	
	/**
	 * Construct an event obj
	 * @param {Object} parseObj
	 * @param {Object} context
	 */
	getEventObj: function(parseObj, context) {
		var eventObj = m3gen.util.getEventObjVP(context)			
		eventObj.parseObj = parseObj;
		return eventObj;
	},	

	
	getEventLvName: function(handlerName) {
		if (handlerName.match("Error")) {
			return "error";
		}
		if (handlerName.match("Warning")) {
			return "warning";			
		}
		if (handlerName.match("Begin") || handlerName.match("Complete")) {
			return "bc";			
		}		
		return "info";				
	},	
	getEventLv: function(handlerName) {
		return this.getEH_lv(this.getEventLvName(handlerName));
	},
	getEHlvs: function(options){
		var isEHlv = m3gen.util.isEHlv;
		return {
			isBCLv: isEHlv(options, m3gen.constants.EH_BC),		
			isInfoLv: isEHlv(options, m3gen.constants.EH_INFO),		
			isWarnLv: isEHlv(options, m3gen.constants.EH_WARNING),
			isErrorLv: isEHlv(options, m3gen.constants.EH_ERROR)
		}
	},
	isEHlv: function(options, testLv){
		var getEH_lv = m3gen.util.getEH_lv;
		var EH_lv = getEH_lv(options.eventHandlerLevel || "error");
		return (EH_lv >= testLv)
	},
	getEH_lv: function(strEH_lv) {
		switch (strEH_lv) {
			case "none": return m3gen.constants.EH_NONE;
			case "error": return m3gen.constants.EH_ERROR;
			case "warning": return m3gen.constants.EH_WARNING;
			case "info": return m3gen.constants.EH_INFO;	
			case "bc": return m3gen.constants.EH_BC;		
			default: return m3gen.constants.EH_ERROR;			
		}
	}	
}

m3gen.pathFunctions = {
	
	findObjByXPath: function(obj, childPath) {
		return $(obj).jpath(childPath);
	},	
	findObjByJPath: function(obj, childPath) {
		return jsonPath(obj, childPath);
	}
}
